home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Stuart's Tech Notes / AppleTalk Zone List.c < prev    next >
Text File  |  1994-12-12  |  8KB  |  269 lines

  1. /* (C) 1993 Stuart Cheshire <cheshire@cs.stanford.edu>
  2.  
  3. This sample code can be used to obtain a list of AppleTalk Zones on the
  4. network. It uses an efficient sorting algorithm to sort a large number
  5. zone names into alphabetical order in an acceptable length of time.
  6. I'm making this public because a shocking number of programs, like MacTCP,
  7. Shiva Net Manager, Spectre Supreme etc. are unable to do this. The Stanford
  8. network has over 200 zones, and on a Mac SE it takes *over a minute* just
  9. to open the MacTCP Control Panel!
  10.  
  11. MAX_ZONES is set to 1000 by default, which should be enough for most networks.
  12.  
  13. You should create a List Manager list, and then call getzonelist to fill it.
  14.  
  15. eg.
  16.     static Rect initial_list = { 0,0,0,1 };
  17.     static Point list_cell_size = { 0,0 };
  18.     
  19.     GetDItem(modaldialog, zonelist_item, &di_type, &di_handle, &di_box);
  20.                                     // Read useritem bounds from DITL
  21.     di_box.right -= 15;                // Make room for the vertical scroll bar
  22.     zonelist = LNew(&di_box, &initial_list, list_cell_size, 0, modaldialog,
  23.         TRUE, FALSE, FALSE, TRUE);    // Create the list
  24.  
  25.  
  26.     LDoDraw(FALSE, zonelist);        // Turn off list drawing
  27.     num_appletalk_zones = getzonelist(zonelist, mydomain.c);
  28.                                     // Get the list of zones    
  29.     pt.h = pt.v = 0;
  30.     LSearch(&myzone.c[1], myzone.c[0], NULL, &pt, zonelist);
  31.     LSetSelect(TRUE, pt, zonelist);    // select home zone as default
  32.     LAutoScroll(zonelist);            // scroll it into view
  33.     LDoDraw(TRUE, zonelist);        // and turn on list drawing again.
  34.  
  35.  
  36. Tab stops are four spaces
  37.  
  38. /*****************************************************************************/
  39.  
  40. #include <AppleTalk.h>
  41. #include <Packages.h>
  42.  
  43. #include "StuTypes.h"
  44. #include "StuAppleTalk.h"
  45.  
  46. /*****************************************************************************/
  47.  
  48. #define atpMaxData     578             // size of buffer for zone names
  49. #define kZIPSocket     6             // the Zone Information Protocol socket
  50. #define kATPTimeOutVal 3             // re-try ATP SendRequest every 3 seconds
  51. #define kATPRetryCount 5             // for five times
  52. #define kGZLCall       0x08000000    // GetZoneList indicator
  53. #define kGMZCall       0x07000000    // GetMyZone indicator
  54. #define kZoneCount     0x0000FFFF     // mask to count zones in buffer
  55. #define kNoMoreZones   0xFF000000     // mask to see if more zones to come
  56.  
  57. #define xCall               246
  58. #define zipGetLocalZones    5
  59. #define zipGetZoneList      6
  60. #define zipGetMyZone        7
  61.  
  62. typedef struct
  63.     {
  64.     QElemPtr  qLink;
  65.     short     qType;
  66.     short     ioTrap;
  67.     Ptr       ioCmdAddr;
  68.     ProcPtr   ioCompletion;
  69.     OSErr     ioResult;
  70.     StringPtr ioNamePtr;
  71.     short     ioVRefNum;
  72.     short     ioRefNum;
  73.     short     csCode;
  74.     short     xppSubCode;
  75.     u_char    xppTimeOut;
  76.     u_char    xppRetry;
  77.     short     filler;
  78.     Ptr       zipBuffPtr;
  79.     short     zipNumZones;
  80.     short     zipLastFlag;
  81.     short     zipInfoField[35];
  82.     } xCallParam;
  83.  
  84. /*****************************************************************************\
  85.  
  86. These global variables hold the zone names, the heap of pointers used to
  87. sort them, and the counter which says how many zones there are on the heap.
  88.  
  89. The code could be made more elegant (and re-entrant) if the routines were
  90. wrapped up into a "ZoneList" C++ object, and the globals could then be made
  91. private class member variables.
  92. */
  93.  
  94. #define MAX_ZONES 1000
  95. typedef struct { u_char c[34]; } ZONE_NAME;
  96. local ZONE_NAME *zone_array, **zone_heap;
  97. local short num_zones;
  98.  
  99. /*****************************************************************************\
  100.  
  101. These two routines are used to sort the zone list into alphabetical order
  102. */
  103.  
  104. local void ZL_addtoheap(int place, ZONE_NAME *new)
  105.     {
  106.     int parent = (place-1)>>1;
  107.     zone_heap[place]=new;
  108.     while (place>0 && IUCompString(zone_heap[parent]->c, zone_heap[place]->c)>0)
  109.         {
  110.         ZONE_NAME *temp   = zone_heap[place ];
  111.         zone_heap[place ] = zone_heap[parent];
  112.         zone_heap[parent] = temp;
  113.         place=parent;
  114.         parent=(place-1)>>1;
  115.         }
  116.     }
  117.  
  118. local ZONE_NAME *ZL_removefromheap(int last)// last is index of last item on heap
  119.     {
  120.     ZONE_NAME *top = zone_heap[0];            // extract top element
  121.     int gap   = 0;                            // top is now empty
  122.     int left  = 1;
  123.     int right = 2;
  124.     while(left<=last)                        // move gap to bottom
  125.         {
  126.         if(right>last || IUCompString(zone_heap[right]->c, zone_heap[left]->c)>0)
  127.             { zone_heap[gap]=zone_heap[left ]; gap=left;  }
  128.         else{ zone_heap[gap]=zone_heap[right]; gap=right; }
  129.         left  = (gap<<1)+1;
  130.         right = left + 1;
  131.         }
  132.     if(last != gap) ZL_addtoheap(gap, zone_heap[last]);    // fill gap
  133.     return(top);    // and heap is now one element smaller
  134.     }
  135.  
  136. /*****************************************************************************\
  137.  
  138. This routine (the old method) is used if AppleTalk Phase Two is not available
  139. */
  140.  
  141. local void BuildZoneListPhase1(u_char *myzone)
  142.     {
  143.     ATPParamBlock pb;
  144.     BDSElement    dBDS;
  145.     u_char        datapacket[atpMaxData];
  146.     short         i;
  147.     
  148.     dBDS.buffSize    = atpMaxData;
  149.     dBDS.buffPtr     = (Ptr)datapacket;
  150.  
  151.     pb.ATPatpFlags   = 0;
  152.     pb.ATPreqLength  = 0;
  153.     pb.ATPreqPointer = NULL;
  154.     pb.ATPbdsPointer = (Ptr) &dBDS;
  155.     pb.ATPnumOfBuffs = 1;
  156.     pb.ATPtimeOutVal = kATPTimeOutVal;
  157.     pb.ATPretryCount = kATPRetryCount;
  158.  
  159.     pb.ATPaddrBlock.aNet    = ABusVars->sysNetNum;
  160.     pb.ATPaddrBlock.aNode   = GetBridgeAddress();
  161.     pb.ATPaddrBlock.aSocket = kZIPSocket;
  162.  
  163.     if (!pb.ATPaddrBlock.aNode) return;        // no bridge -- no zones
  164.  
  165.     do    {
  166.         u_char *ptr = datapacket;
  167.         pb.ATPuserData = kGZLCall + num_zones + 1;
  168.         PSendRequest(&pb, false);
  169.         i = dBDS.userBytes & kZoneCount;
  170.         while(--i >= 0)
  171.             {
  172.             int count = 1 + *ptr;
  173.             u_char *dest = zone_array[num_zones].c;
  174.             while (count-- > 0) *dest++ = *ptr++;
  175.             ZL_addtoheap(num_zones, &zone_array[num_zones]);
  176.             num_zones++;
  177.             }
  178.         } until(dBDS.userBytes & kNoMoreZones);
  179.     
  180.     pb.ATPuserData = kGMZCall;
  181.     datapacket[0] = 0;
  182.     if (PSendRequest(&pb, false) == noErr && datapacket[0] && datapacket[0]<32)
  183.         for (i=0; i<=datapacket[0]; i++) myzone[i] = datapacket[i];
  184.     }
  185.  
  186. /*****************************************************************************\
  187.  
  188. This routine (the new method) should be used in almost all cases these days
  189. */
  190.  
  191. local void BuildZoneListPhase2(u_char *myzone)
  192.     {
  193.     short      XPPRefNum;
  194.     xCallParam xpb;
  195.     u_char     datapacket[atpMaxData];
  196.     
  197.     if (OpenDriver("\p.XPP", &XPPRefNum)) return;
  198.  
  199.     xpb.zipInfoField[0] = 0;
  200.     xpb.zipInfoField[1] = 0;
  201.     xpb.zipLastFlag = FALSE;
  202.     xpb.ioRefNum    = XPPRefNum;
  203.     xpb.csCode      = xCall;
  204.     xpb.xppSubCode  = zipGetZoneList;
  205.     xpb.xppTimeOut  = kATPTimeOutVal;
  206.     xpb.xppRetry    = kATPRetryCount;
  207.     xpb.zipBuffPtr  = (Ptr)datapacket;
  208.  
  209.     while (!xpb.zipLastFlag && PBControl((ParmBlkPtr)&xpb, FALSE) == noErr)
  210.         {
  211.         u_char *ptr = datapacket;
  212.         short i = xpb.zipNumZones;
  213.         while(--i >= 0)
  214.             {
  215.             int namelength = 1 + *ptr;
  216.             u_char *dest = zone_array[num_zones].c;
  217.             while (namelength-- > 0) *dest++ = *ptr++;
  218.             ZL_addtoheap(num_zones, &zone_array[num_zones]);
  219.             num_zones++;
  220.             }
  221.         }
  222.  
  223.     xpb.zipInfoField[0] = 0;
  224.     xpb.zipInfoField[1] = 0;
  225.     xpb.xppSubCode  = zipGetMyZone;
  226.     xpb.zipBuffPtr  = (Ptr)myzone;
  227.     PBControl((ParmBlkPtr)&xpb, FALSE);
  228.     // Mustn't close XPP driver (see IM V 532)
  229.     }
  230.  
  231. /*****************************************************************************\
  232.  
  233. This routine fills the given ListHandle with the list of zone names,
  234. in alphabetical order, and also puts the name of the 'home' zone for
  235. this Machintosh in the string pointed to by myzone. The return value
  236. is the number of zone names put into the ListHandle.
  237. */
  238.  
  239. short getzonelist(ListHandle zonelist, u_char *myzone)
  240.     {
  241.     myzone[0] = num_zones = 0;
  242.     zone_array = (ZONE_NAME  *) NewPtr(MAX_ZONES * sizeof(ZONE_NAME  ));
  243.     zone_heap  = (ZONE_NAME **) NewPtr(MAX_ZONES * sizeof(ZONE_NAME *));
  244.  
  245.     if (zone_array && zone_heap)
  246.         {
  247.         short i;
  248.         SysEnvRec sysenvirons;
  249.         SysEnvirons(1, &sysenvirons);
  250.         if (sysenvirons.atDrvrVersNum < 53) BuildZoneListPhase1(myzone);
  251.         else                                BuildZoneListPhase2(myzone);
  252.             
  253.         i = num_zones;
  254.         while (--i>=0)
  255.             {
  256.             Point pt = { 0, 0 };
  257.             ZONE_NAME *name = ZL_removefromheap(i);
  258.             pt.v = (*zonelist)->dataBounds.bottom;
  259.             LAddRow(1, pt.v, zonelist);
  260.             LSetCell(&name->c[1], name->c[0], pt, zonelist);
  261.             }
  262.         }
  263.     
  264.     if (zone_array) DisposPtr((Ptr)zone_array);
  265.     if (zone_heap ) DisposPtr((Ptr)zone_heap);
  266.  
  267.     return(num_zones);
  268.     }
  269.